package com.wenx.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.io.File;
import java.net.URL;
import java.util.*;

public class RpcServer {

    //不用考虑多线程，nio模型
    //存放类名称
    private List<String> classCache = new ArrayList<>();
    //private List<String> classCache = Collections.synchronizedList(new ArrayList<>());    线程安全的list

    //key 是类的接口，value是类的实例
    private Map<String,Object> registerMap = new HashMap<>();


    /**
     * 发布
     * @param providerPackage    formate com.wenx.service.xxx
     */
    public void publish(String providerPackage) throws Exception {

        //将制定包下的提供者名称写入到classCache中
        getProviderClass(providerPackage);
        //将提供者名称与提供者实例之间的映射关系写入到registerMap中
        doRegister();

        //nio模型获取client连接
        EventLoopGroup bossGroup = new NioEventLoopGroup();//当前CPU内核数量的两倍
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,workerGroup)
                    //客户端请求队列数，default = 50
                    .option(ChannelOption.SO_BACKLOG,1024)
                    //使用心跳维护长连接
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            //InvokeMessage 客户端发送消息设置
                            //ObjectDecoder 解码器
                            pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE,
                                     ClassResolvers.cacheDisabled(null)));
                            //服务器端返回消息设置
                            //编码,添加编码器
                            pipeline.addLast(new ObjectEncoder());
                            //自定义处理器
                            pipeline.addLast(new RpcServerHandler(registerMap));
                        }
                    });
            ChannelFuture future = serverBootstrap.bind(8888).sync();
            System.out.println(" 服务器已经启动 ");
            future.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }

    private void doRegister() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        if (classCache.size()==0) {
            return;
        }

        for (String className : classCache) {
            Class<?> aClass = Class.forName(className);
            //服务类一般只有一个接口
            Class<?> anInterface = aClass.getInterfaces()[0];
            Object instance = aClass.newInstance();
            registerMap.put(anInterface.getName(),instance);
        }

    }

    private void getProviderClass(String providerPackage) {
        URL resource = this.getClass().getClassLoader().getResource(providerPackage.replaceAll("\\.", "/"));

        if (resource != null) {
            //将URL转化为file
            File dir = new File(Objects.requireNonNull(resource).getFile());
            //获取包下的.class文件
            for (File file : Objects.requireNonNull(dir.listFiles())) {
                if (file.isDirectory()) {
                    //递归获取下面的.class文件
                    getProviderClass(providerPackage+"."+file.getName());
                } else if(file.getName().endsWith(".class")) {
                    //只处理.class类型的文件
                    classCache.add(providerPackage+"."+file.getName().replace(".class","").trim());
                }
            }
        }

    }

}
